/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.vdialog.model.template;

import javax.swing.text.Document;
import javax.swing.tree.DefaultMutableTreeNode;
import offset.nodes.Constants;
import offset.nodes.client.vdialog.model.template.AbstractTemplateNode;
import offset.nodes.client.model.StringArrayConverter;
import offset.nodes.client.vdialog.model.template.TemplateNode;
import offset.nodes.client.vdialog.model.template.TemplateReferenceNode;
import offset.nodes.client.model.TreeNodeUserObject;
import offset.nodes.client.virtual.model.jcr.QName;
import offset.nodes.client.vdialog.model.PrintDocumentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
 *
 * @author Walter Lütgenau
 */
public class TemplateDefinitionWriter extends AbstractTreeDefinitionWriter {

    public TemplateDefinitionWriter(Document document) {
        super(new PrintDocumentHandler(document));
    }

    /**
     * Print the node and its attributes, including the child nodes
     * 
     * @param node the node
     * @throws org.xml.sax.SAXException
     */
    protected void printNode(DefaultMutableTreeNode node) throws Exception {
        Object userObject = node.getUserObject();
        Object parentObject = null;
        if (node.getParent() != null) {
            parentObject = ((DefaultMutableTreeNode) node.getParent()).getUserObject();
        }

        if (userObject instanceof AbstractTemplateNode) {
            printStartTemplateNode(parentObject, (AbstractTemplateNode) userObject);
        } else if (userObject instanceof TemplateNode) {
            printStartTemplate(node, (TemplateNode) userObject);
        }

        for (int i = 0; i < node.getChildCount(); i++) {
            printNode((DefaultMutableTreeNode) node.getChildAt(i));
        }

        if (userObject instanceof TreeNodeUserObject) {
            printEnd(parentObject, (TreeNodeUserObject) userObject);
        }

    }

    /**
     * Print the first part of the XML: the start tag and the attributes. Leave the end open
     * to be able to include the children
     * 
     * @param node
     * @throws org.xml.sax.SAXException
     */
    protected void printStartTemplateNode(Object parentObject, AbstractTemplateNode node) throws Exception {
        AttributesImpl atts = new AttributesImpl();

        // add template node
        addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.TYPE_TEMPLATE_NODE);
        addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);

        if (node.getUuid() != null) {
            addAttribute(atts, Constants.JCR_UUID, node.getUuid());
        }

        if (node.getQuery() != null) {
            addAttribute(atts, Constants.PROP_PRIMARY_QUERY, node.getQuery());
        }

        if (node.getType().equals(AbstractTemplateNode.TYPE_VIRTUAL_PAGE) && ((PageNode) node).getPage() != null) {
            String[] secondaryQueries = ((PageNode) node).getPage().getSecondaryQueries();
            if (secondaryQueries != null && secondaryQueries.length > 0) {
                StringArrayConverter sa = new StringArrayConverter(secondaryQueries);
                addAttribute(atts, Constants.PROP_SECONDARY_QUERY, sa.toString());
            }
        }

        String name = null;
        if (parentObject instanceof TemplateNode) {
            name = Constants.CHILD_ROOT;
        } else if (parentObject instanceof AbstractTemplateNode) {
            name = Constants.CHILD_TEMPLATE_NODE_CHILD;
        }

        startElement(name, atts);

        // add presentation node
        atts =
                new AttributesImpl();
        if (node.getType() != null) {
            addAttribute(atts, Constants.JCR_PRIMARY_TYPE, node.getType());
        }
        
        if ( node instanceof PageNode) {
            
        }

        if (node.getNodeType() != null) {
            QName nodeType = node.getNodeType().getName();
            addAttribute(atts, Constants.PROP_NODETYPE, toPrefixName(nodeType));
        }

        if (node instanceof PathNode) {
            PathNode pathNode = (PathNode) node;
            if (pathNode.getName() != null && pathNode.getName().length() > 0) {
                addAttribute(atts, Constants.PROP_NAME, pathNode.getName());
            }

            if (pathNode.getNameProperty() != null) {
                addAttribute(atts, Constants.PROP_NAME_PROPERTY, pathNode.getNameProperty());
            }
            
            if ( pathNode.getRepresentationUuid() != null)
                addAttribute(atts, Constants.JCR_UUID, pathNode.getRepresentationUuid());

        } else if (node instanceof TemplateReferenceNode) {
            TemplateReferenceNode referenceNode = (TemplateReferenceNode) node;
            if (referenceNode.getTemplatePath() != null) {
                addAttribute(atts, Constants.PROP_REFERENCE, referenceNode.getTemplatePath());
            }

        }

        addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);
        startElement(Constants.CHILD_REPRESENTATION, atts);

        if (node.getType().equals(AbstractTemplateNode.TYPE_VIRTUAL_PAGE) && ((PageNode) node).getPage() != null) {
            PageNode page = (PageNode) node;

            atts = new AttributesImpl();
            addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.JCR_FILE);
            addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);
            if ( page.getSampleUuid() != null)
                addAttribute(atts, Constants.JCR_UUID,page.getSampleUuid());
            
            startElement(Constants.CHILD_SAMPLE, atts);
            characters(page.getPage().getSampleHtml().toCharArray(), 0, page.getPage().getSampleHtml().length());
            endElement(Constants.CHILD_SAMPLE);

            atts = new AttributesImpl();
            addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.JCR_FILE);
            addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);
            if ( page.getTransformationUuid() != null)
                addAttribute(atts, Constants.JCR_UUID,page.getTransformationUuid());
            
            startElement(Constants.CHILD_TRANSFORMATION, atts);
            characters(page.getPage().getStyleSheet().toCharArray(), 0, page.getPage().getStyleSheet().length());
            endElement(Constants.CHILD_TRANSFORMATION);

            atts = new AttributesImpl();
            addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.JCR_FILE);
            if ( page.getEditorTransformationUuid() != null)
                addAttribute(atts, Constants.JCR_UUID,page.getEditorTransformationUuid());

            startElement(Constants.CHILD_EDITORTRANSFORMATION, atts);
            characters(page.getPage().getEditorStyleSheet().toCharArray(), 0, page.getPage().getEditorStyleSheet().length());
            endElement(Constants.CHILD_EDITORTRANSFORMATION);

            if (page.getPage().getCascadingStyleSheet() != null) {
                atts = new AttributesImpl();
                addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.JCR_UNSTRUCTURED);
                addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);
                addAttribute(atts, Constants.PROP_CONTENT_TYPE, "css");
                if ( page.getCssUuid() != null)
                    addAttribute(atts, Constants.JCR_UUID,page.getCssUuid());
               
                startElement(Constants.CHILD_CSS, atts);

                atts = new AttributesImpl();
                addAttribute(atts, Constants.JCR_PRIMARY_TYPE, Constants.JCR_FILE);
                addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);
                if ( page.getCssBodyUuid() != null)
                    addAttribute(atts, Constants.JCR_UUID,page.getCssBodyUuid());
                startElement(Constants.NODES_BODY, atts);
                characters(page.getPage().getCascadingStyleSheet().toCharArray(), 0, page.getPage().getCascadingStyleSheet().length());
                endElement(Constants.NODES_BODY);

                endElement(Constants.CHILD_CSS);
            }
        }

        endElement(Constants.CHILD_REPRESENTATION);
    }

    /**
     * Print the closing tag of the node
     * 
     * @param node
     * @throws org.xml.sax.SAXException
     */
    protected void printEnd(Object parentObject, TreeNodeUserObject node) throws SAXException {
        String name = null;
        if (parentObject instanceof TemplateNode) {
            name = Constants.CHILD_ROOT;
        } else if (parentObject instanceof AbstractTemplateNode) {
            name = Constants.CHILD_TEMPLATE_NODE_CHILD;
        } else if (parentObject == null && node instanceof TemplateNode) {
            name = ((TemplateNode) node).getName();
        }

        endElement(name);
    }

    protected String findRootNodeType(DefaultMutableTreeNode node) throws Exception {
        if (node.getChildCount() == 0) {
            return null;
        }

        DefaultMutableTreeNode representation = (DefaultMutableTreeNode) node.getChildAt(0);
        if (representation.getUserObject() == null) {
            return null;
        }

        return toPrefixName(((AbstractTemplateNode) representation.getUserObject()).getNodeType().getName());
    }

    protected void printStartTemplate(DefaultMutableTreeNode template, TemplateNode node) throws Exception {
        AttributesImpl atts = new AttributesImpl();

        addAttribute(atts, Constants.JCR_MIXIN_TYPES, Constants.JCR_VERSIONABLE);

        if (node.getType() != null) {
            addAttribute(atts, Constants.JCR_PRIMARY_TYPE, node.getType());
        }

        if (node.getUuid() != null) {
            addAttribute(atts, Constants.JCR_UUID, node.getUuid());
        }

        String rootNodeType = findRootNodeType(template);
        if (rootNodeType != null) {
            addAttribute(atts, Constants.PROP_NODETYPE, rootNodeType);
        }

        addAttribute(atts, Constants.PROP_NAME, node.getName()); // will be removed as soon as removing the node type property is possible

        startElement(node.getName(), atts);

    }
}
